package utils;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import net.sbbi.upnp.impls.InternetGatewayDevice;
import upnp.IpUtils;

public class NetworkUtils {

	
	/**
	 * Vraca IP adresu iz socket adrese oblika "/IP:port".
	 * 
	 * @param sa -
	 *            SocketAddress
	 * @return IP
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public static final String getIPFromSockeAddress(SocketAddress sa) {
		String str = sa.toString();

		int ind = str.lastIndexOf(":");

		String retStr = str.substring(1, ind);

		return retStr;
	}
	
	

	public static List<InetAddress> getLocalAddresses() throws SocketException {
		List<InetAddress> addresses = new ArrayList<InetAddress>();

		for (Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces(); e.hasMoreElements();) {
			NetworkInterface intf = e.nextElement();
			Enumeration<InetAddress> adrs = intf.getInetAddresses();
			while (adrs.hasMoreElements()) {
				InetAddress adr = adrs.nextElement();
				if ((adr instanceof Inet4Address) && !adr.isLoopbackAddress()) {
					// System.out.println(adr.getHostAddress());
					addresses.add(adr);
				}
			}
		}

		return addresses;
	}

	public static InetAddress getLocalAddress(InetAddress gateway) throws SocketException {
		int max = -1;
		byte[] gatewayip = gateway.getAddress();
		InetAddress local = null;
		for (InetAddress localAddress : getLocalAddresses()) {
			int i;
			byte[] localip = localAddress.getAddress();
			for (i = 0; (i < localip.length) && (i < gatewayip.length) && (localip[i] == gatewayip[i]); i++)
				;
			if (i > max) {
				max = i;
				local = localAddress;
			}
		}
		return local;
	}

	
	public static InetAddress getLocalAddress() {
		
		int DiscoveryTimeout = 4000;
		
		InetAddress localAddress = null;
		
		try {
			InternetGatewayDevice[] IGDs = InternetGatewayDevice.getDevices(DiscoveryTimeout);

			if ( IGDs != null ) {
				InternetGatewayDevice testIGD = IGDs[0];
				
				localAddress = IpUtils.getLocalAddress(testIGD.getIGDRootDevice().getInetAddress());
				
				return localAddress;
			}
			else {
				return null;
			}
		} catch (IOException ioe) {
			return null;
		}
	}
	
	
	/*	
	public static InetAddress obtainLocalAdress()
	{
		// obtain local host address (fallback case)
		InetAddress addr = null;
		try {
			addr = InetAddress.getLocalHost();
		} catch (UnknownHostException eUHE) {
			return null;
		}
		boolean found = false;

		if (!found)
		{
			// obtain list of network interfaces
			try {

				Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();

				// check if we got something
				if (interfaces != null) {
					// loop for all interfaces
					while (interfaces.hasMoreElements()) {
						NetworkInterface card = interfaces.nextElement();
						Enumeration<InetAddress> addresses = card.getInetAddresses();
						if (addresses == null)
							continue;

						// log info on current network interface
						while (addresses.hasMoreElements()) {
							InetAddress address = addresses.nextElement();

							// should we bind to this address
							if (found == false) {
								if (!address.isLoopbackAddress())
									if (isIPAddress(address.getAddress()))
										if (isValidAddress(address.getAddress()))
										{
											addr = address;
											found = true;
										}
										else System.out.println("address is not valid - local network or NAT problem");
									else System.out.println("this is not ip adress...");
								else System.out.println("this is loopback address!");
							}
						}
					}
				} else
					System.out.println("list of network interfaces is empty, using default localhost!");
			} catch (SocketException eSE) {

			}
		}
		return addr;
	}
	
	private static boolean isValidAddress(byte[] ip) {
//		if (port > 20000)
//		return false;

		if (!isIPAddress(ip))
			return false;

		int ip0 = ubyte(ip[0]);
		int ip1 = ubyte(ip[1]);

		if ((ip0 == 192) && (ip1 == 168))
			return false;
		if ((ip0 == 169) && (ip1 == 254))
			return false;
		if (ip0 == 10)
			return false;
		if (ip0 == 127)
			return false;
		return true;
	}

	private static boolean isIPAddress(byte[] ip) {
		if (ip.length!=4) {
			return false;
		}
		int ip0 = ubyte(ip[0]);
		int ip1 = ubyte(ip[1]);
		int ip2 = ubyte(ip[2]);
		int ip3 = ubyte(ip[3]);

		if ((ip0 == 0) | (ip0 == 255) | (ip1 == 255) | (ip2 == 255)
				| (ip3 == 0) | (ip3 == 255))
			return false;
		return true;
	}
	
	public static int ubyte(byte b) {
		return b & 255;
	}
*/	
}
